// NOTE: This example is just for illustration of one possible evolution of Async Move.
// Nothing here is implemented.

#[actor]
/// This is an instance of the Account example using continuations.
///
/// In this model each function gets passed an (opaque) representation of a continuation with which to continue
/// executing once it is done. We model the creation of continuations via attribute based code generation.
/// (See end of the module.)
module This::AccountContinuation {

    use Async::Unit::Unit;
    use Async::Cont::{Cont, done};

    const MAX: u64 = 43;

    #[state]
    struct Account {
        value: u64
    }

    #[init]
    fun init(): Account {
        Account{value: 0}
    }

    #[rpc]
    fun deposit(this: &mut Account, v: u64, cont: Cont<Unit>) {
        this.value = this.value + v;
        done(cont)
    }

    #[rpc]
    fun withdraw(this: &mut Account, v: u64, cont: Cont<Unit>) {
        this.value = this.value - v;
        done(cont)
    }

    #[rpc]
    fun xfer(this: &Account, dest: address, v: u64, cont: Cont<Unit>) {
        // Do not initiate the transfer if there are not enough funds.
        assert!(this.value >= v, 1);
        // Deposit on the other end, and only if this succeeds, withdraw here.
        send_deposit(dest, v, cont_xfer_withdraw(v, cont))
    }

    #[cont]
    fun xfer_withdraw(this: &mut Account, _previous: Unit, v: u64, cont: Cont<Unit>) {
        withdraw(this, v, cont)
    }

    // ===============================================================
    // The following native function definitions are automatically
    // generated by a Move attribute preprocessor, and implemented
    // automatically by the runtime environment.

    #[_generated_send]
    public native fun send_deposit(dest: address, v: u64, cont: Cont<Unit>);

    #[_generated_cont]
    native fun cont_xfer_withdraw(v: u64, cont: Cont<Unit>): Cont<Unit>;
}

/// Continuation support -- currently not in the Async library
module Async::Cont {
    use Async::Unit::{Unit, unit};

    /// A type which represents a continuation.
    native struct Cont<T> has drop;

    /// Continues execution with the given continuation, passing in the result from the previous step.
    public native fun next<T>(cont: Cont<T>, result: T);

    /// Shortcut for `next(cont, unit())`
    public fun done(cont: Cont<Unit>) {
        next(cont, unit())
    }
}
